#ifndef __RING_QUEUE_HPP
#define __RING_QUEUE_HPP
#include <vector>
#include <semaphore.h>
#include <pthread.h>
template <class T>
class RingQueue
{
private:
    void P(sem_t *sem)
    {
        sem_wait(sem);
    }
    void V(sem_t *sem)
    {
        sem_post(sem);
    }

public:
    RingQueue(int cap) : _cap(cap), _ring_queue(cap), _productor_step(0), _consumer_step(0)
    {
        sem_init(&_space_sem, 0, cap); // 一开始空间资源是满的
        sem_init(&_data_sem, 0, 0);    // 一开始没有数据
        pthread_mutex_init(&_productor_mutex, nullptr);
        pthread_mutex_init(&_consumer_mutex, nullptr);
    }

    void Enqueue(T in) // 生产者生产接口
    {
        // 先预定一个空间资源，空间信号量p操作
        P(&_space_sem);
        pthread_mutex_lock(&_productor_mutex);
        // P操作成功一定有空间可以消费且生产者和消费者的下标不相同
        _ring_queue[_productor_step] = in;
        _productor_step++;
        // 生产成功后，保证环形队列的特性且对数据信号量V操作
        _productor_step %= _cap;
        pthread_mutex_unlock(&_productor_mutex);
        V(&_data_sem);
    }
    void Pop(T &out)
    {
        // 先预定一个数据资源，数据信号量p操作
        P(&_data_sem);
        pthread_mutex_lock(&_consumer_mutex);
        // P操作成功一定有数据可以消费且生产者和消费者的下标不相同
        out = _ring_queue[_consumer_step++];
        // 消费成功后，保证环形队列的特性且对空间信号量V操作
        _consumer_step %= _cap;
        pthread_mutex_unlock(&_consumer_mutex);
        V(&_space_sem);
    }

    ~RingQueue()
    {
        sem_destroy(&_space_sem);
        sem_destroy(&_data_sem);
        pthread_mutex_destroy(&_productor_mutex);
        pthread_mutex_destroy(&_consumer_mutex);
    }

protected:
    // 数据结构
    std::vector<T> _ring_queue; // 环形队列
    const int _cap;             // 环形队列的总大小

    // 生产消费所处的下标
    int _productor_step;
    int _consumer_step;

    // 信号量
    sem_t _space_sem; // 空间信号量
    sem_t _data_sem;  // 数据信号量

    // 互斥锁
    pthread_mutex_t _productor_mutex; // 多生产者使用的互斥锁
    pthread_mutex_t _consumer_mutex;  // 多消费者使用的互斥锁
};

#endif
